package com.yzt.javacv;

import java.io.File;
import java.util.Date;
import java.util.concurrent.atomic.AtomicInteger;

import org.bytedeco.javacpp.avcodec;
import org.bytedeco.javacpp.avutil;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.FFmpegFrameRecorder;
import org.bytedeco.javacv.Frame;

/**
 * @author Yang_ZT
 *
 */
public class VideoCompression {

	private static final int FRAME_RATE = 30;
	private static final int VIDEO_BITRATE = 1048576;
	private static final int COMPRESS_WIDTH = 1920;

	/**
	 * 在使用时发现视频压缩和视频时长有关系 一个9M的56s的视频压缩后视频7M多 一个22M的5s的视频压缩后视频624K
	 * 
	 * @param file
	 * @param checkCompress
	 * @return
	 * @throws Exception
	 */
	public static boolean compression(String filePaht) {
		try {
			File file = new File(filePaht);
			if (!file.isFile() || !file.exists()) {
				App.jTextArea.append(App.sdf.format(new Date()) + "--当前地址视频不存在，请重试!!\n");
				App.jScrollBar.setValue(App.jScrollBar.getMaximum());
				App.isRun = false;
				return false;
			}

			FFmpegFrameGrabber frameGrabber = new FFmpegFrameGrabber(file.getAbsolutePath());
			String fileName = null;

			Frame captured_frame = null;

			FFmpegFrameRecorder recorder = null;
			
			

			String suffix = file.getName().substring(file.getName().lastIndexOf("."), file.getName().length());

			frameGrabber.start();
			fileName = file.getAbsolutePath().replace(suffix, "_edited" + suffix);

			int height = frameGrabber.getImageHeight();
			int width = frameGrabber.getImageWidth();
			double frameRate = frameGrabber.getFrameRate() > FRAME_RATE ? FRAME_RATE : frameGrabber.getFrameRate();
			if (needCompress(file.length()) && width > COMPRESS_WIDTH) {
				height = calculateHeight(frameGrabber.getImageWidth(), frameGrabber.getImageHeight(), COMPRESS_WIDTH);
				width = COMPRESS_WIDTH;
			}
			recorder = new FFmpegFrameRecorder(fileName, width, height, frameGrabber.getAudioChannels());
			recorder.setFrameRate(frameRate);
			// 下面这行打开就报错
			// recorder.setSampleFormat(frameGrabber.getSampleFormat());
			recorder.setSampleRate(frameGrabber.getSampleRate());
			// recorder.setAudioChannels(1);
			recorder.setVideoOption("preset", "veryfast");
			// yuv420p,像素
			recorder.setPixelFormat(avutil.AV_PIX_FMT_YUV420P);
			recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
			recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);
			recorder.setFormat(suffix);
			// 比特
//			 recorder.setVideoBitrate(VIDEO_BITRATE);
			recorder.setVideoBitrate((int) (width * height * frameRate * App.GLOBAL_SCALE));

			App.jTextArea.append(App.sdf.format(new Date()) + "--视频开始压缩，开始时间:" + App.sdf.format(new Date()) + "\n");
			App.jScrollBar.setValue(App.jScrollBar.getMaximum());

			long start = System.currentTimeMillis();

			long t = System.currentTimeMillis();

			recorder.start();

			AtomicInteger currentIndex = new AtomicInteger(0);
			currentIndex.addAndGet(1);
			
			while (true) {
				captured_frame = frameGrabber.grabFrame();
				if (captured_frame == null) {
					App.jTextArea.append(App.sdf.format(new Date()) + "--!!! end cvQueryFrame\n");
					App.jScrollBar.setValue(App.jScrollBar.getMaximum());
					break;
				}
				recorder.setTimestamp(frameGrabber.getTimestamp());
				recorder.record(captured_frame);

				if ((System.currentTimeMillis() - t) / 1000 == currentIndex.get()) {

					App.jTextArea.append(
							App.sdf.format(new Date()) + "--压缩历时:" + ((System.currentTimeMillis() - t) / 1000) + "秒\n");
					App.jScrollBar.setValue(App.jScrollBar.getMaximum());

					currentIndex.addAndGet(1);
				}

			}
			recorder.stop();
			recorder.release();
			frameGrabber.stop();
			frameGrabber.close();
			recorder.close();

			App.jTextArea.append(
					App.sdf.format(new Date()) + "--视频压缩总历时：" + ((System.currentTimeMillis() - start) / 1000) + "秒\n");

			App.jTextArea.append(App.sdf.format(new Date()) + "--视频压缩成功,请在视频当前目录查找！！\n");
			App.jScrollBar.setValue(App.jScrollBar.getMaximum());
		} catch (Exception e) {
			e.printStackTrace();
			App.jTextArea.append(App.sdf.format(new Date()) + "--视频文件有损坏或不是视频文件，请重新选择文件......\n");
			App.jScrollBar.setValue(App.jScrollBar.getMaximum());
		}
		return true;
	}

	/**
	 * 是否需要压缩，大于3MB
	 * 
	 * @param length
	 * @return
	 */
	public static boolean needCompress(long length) {
		return length >= 3145728;
	}

	/**
	 * 等比计算新高度
	 * 
	 * @param w
	 * @param h
	 * @param nw
	 * @return
	 */
	private static int calculateHeight(int w, int h, int nw) {
		double s = Integer.valueOf(h).doubleValue() / Integer.valueOf(w).doubleValue();
		int height = (int) (nw * s);
		// 如果宽和高不是偶数recorder.start();会报错
		if (height % 2 != 0) {
			height += 1;
		}
		return height;
	}
}
